package Servidor;

import Comunicaciones.SocketCom;
import PaqDatos.*;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
import java.util.Date;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Sesion extends Thread {

    private AulaVirtual _aulaVirtual;
    private Usuario _usuario;
    private String _nombre;
    protected SocketCom socketCom = null;
    protected SocketCom socketComAvisos = null;
    XStream xstream = null;

    public Sesion(AulaVirtual aulaVirtual, String nombre, SocketCom ssocketCom) {
        _aulaVirtual = aulaVirtual;
        _nombre = nombre;
        socketCom = ssocketCom;
        xstream = new XStream(new DomDriver());
        start();
    }

    @Override
    public void run() {

        socketComAvisos = new SocketCom(socketCom.getPeerIP(), socketCom.getLocalPort() + 1);


        do {
            try {
                String pet = socketCom.recibir();

                if (pet == null) {
                    break;
                }

                if (pet.equals("desconectar")) {
                    break;
                } else if (pet.equals("getAsignaturas")) {
                    socketCom.enviar(xstream.toXML(getAsignaturas()).replaceAll("\n", ""));
                } else if (pet.equals("matricular")) {
                    String idAsignatura = socketCom.recibir();
                    matricular(idAsignatura);
                    socketCom.enviar(xstream.toXML(""));
                } else if (pet.equals("getTemasAsignatura")) {
                    String idAsig = socketCom.recibir();
                    socketCom.enviar(xstream.toXML(getTemasAsignatura(idAsig)).replaceAll("\n", ""));
                } else if (pet.equals("anyadirPregunta")) {
                    String idAsig = socketCom.recibir();
                    String idTema = socketCom.recibir();
                    String enunciado = socketCom.recibir();

                    anyadirPregunta(idAsig, idTema, enunciado);

                    socketCom.enviar(xstream.toXML(""));
                } else if (pet.equals("anyadirRespuesta")) {
                    String idP = socketCom.recibir();
                    String enunciadoRespuesta = socketCom.recibir();
                    boolean esCierta = (socketCom.recibir() == "true");

                    anyadirRespuesta(idP, enunciadoRespuesta, esCierta);
                    socketCom.enviar(xstream.toXML(""));
                } else if (pet.equals("getExamenes")) {
                    socketCom.enviar(xstream.toXML(getExamenes()).replaceAll("\n", ""));
                } else if (pet.equals("verNotasDelExamen")) {
                    String idEx = socketCom.recibir();

                    socketCom.enviar(xstream.toXML(verNotasDelExamen(idEx)).replaceAll("\n", ""));
                } else if (pet.equals("verExamenEspecificoAlumno")) {
                    String idEx = socketCom.recibir();
                    String idAlu = socketCom.recibir();

                    socketCom.enviar(xstream.toXML(verExamenEspecificoAlumno(idEx, idAlu)).replaceAll("\n", ""));
                } else if (pet.equals("ponerExamen")) {
                    String idAsig = socketCom.recibir();
                    PaqDatos.InfoTema[] temas = (PaqDatos.InfoTema[]) xstream.fromXML(socketCom.recibir());
                    String fechaIni = socketCom.recibir();
                    String fechaFin = socketCom.recibir();

                    ponerExamen(idAsig, temas, fechaIni, fechaFin);

                    socketCom.enviar(xstream.toXML(""));
                } else if (pet.equals("getNotificacionesExamen")) {
                    socketCom.enviar(xstream.toXML(getNotificacionesExamen()).replaceAll("\n", ""));
                } else if (pet.equals("generarExamen")) {
                    String idEx = socketCom.recibir();

                    socketCom.enviar(xstream.toXML(generarExamen(idEx)).replaceAll("\n", ""));
                } else if (pet.equals("terminarExamen")) {
                    String idEx = socketCom.recibir();
                    InfoExamenEspecifico iee = (InfoExamenEspecifico) xstream.fromXML(socketCom.recibir());

                    terminarExamen(idEx, iee);
                    socketCom.enviar(xstream.toXML(""));
                } else if (pet.equals("verExamenEspecifico")) {
                    String idEx = socketCom.recibir();
                    
                    socketCom.enviar(xstream.toXML(verExamenEspecifico(idEx)).replaceAll("\n", ""));
                } else if (pet.equals("setNoficacionLeida")) {
                    String idNot = socketCom.recibir();

                    setNoficacionLeida(idNot);
                    socketCom.enviar(xstream.toXML(""));
                }
            } catch (excepcion ex) {
                socketCom.enviar(xstream.toXML(ex).replaceAll("\n", ""));
            }
        } while (true);

        desconectar();
    }

    public void setSistema(AulaVirtual aSi) {
        this._aulaVirtual = aSi;
    }

    public void desconectar() {
        _aulaVirtual.deleteSesion(this);
        _usuario.deleteSesion();
		socketCom.terminar();
    }

    public void matricular(String aIdAsignatura) throws PaqDatos.excepcion {

        Asignatura a = _aulaVirtual.findAsignatura(aIdAsignatura);

        if (a != null) {
            _usuario.matricular(a);
        } else {
            throw new PaqDatos.excepcion("No existe la asignatura");
        }
    }

    public void anyadirPregunta(String aIdAsig, String aIdTema, String aEnunciadoP) {
        Profesor profesor;

        profesor = (Profesor) _usuario;
        profesor.anyadirPregunta(aIdAsig, aIdTema, aEnunciadoP);
    }

    public void anyadirRespuesta(String aIdPregunta, String aEnunciadoR, boolean aEsCierta) throws excepcion {
        Profesor profesor;

        profesor = (Profesor) _usuario;
        try {
            profesor.anyadirRespuesta(aIdPregunta, aEnunciadoR, aEsCierta);
        } catch (Exception ex) {
            throw new excepcion(ex.getMessage());
        }

    }

    public void ponerExamen(String aIdAsignatura, PaqDatos.InfoTema[] aTemas, String aFechaIni, String aFechaFin) throws PaqDatos.excepcion {
        Profesor prof = (Profesor) this._usuario;

        SimpleDateFormat formatoDelTexto = new SimpleDateFormat("dd/MM/yyyy");
        Date fechaInicial = null;
        Date fechaFinal = null;
        try {

            fechaInicial = formatoDelTexto.parse(aFechaIni);
            fechaFinal = formatoDelTexto.parse(aFechaFin);
			
			fechaInicial.setYear(fechaInicial.getYear() + 2000);
			fechaFinal.setYear(fechaFinal.getYear() + 2000);

        } catch (ParseException ex) {

            ex.printStackTrace();

        }

        try {
            prof.ponerExamen(aIdAsignatura, aTemas, fechaInicial, fechaFinal);
        } catch (Exception ex) {
            throw new excepcion(ex.getMessage());
        }
    }

    public PaqDatos.InfoExamenEspecifico verExamenEspecifico(String aIdExamen) {
        Examen ex = _aulaVirtual.findExamen(aIdExamen);

        ArrayList<ExamenEspecifico> examenesRealizados = _usuario.getExamenesRealizados();

        for (int i = 0; i < examenesRealizados.size(); i++) {
            if (ex == examenesRealizados.get(i).getExamen()) {
                return examenesRealizados.get(i).getExamenCompleto();
            }
        }


        return null;
    }

    public PaqDatos.InfoExamen[] verNotasDelExamen(String aIdExamen) {
        Profesor prof = (Profesor) _usuario; //Una de las precondiciones es que el usuario sea un profesor. Por lo que no debe haber error en el cast

        PaqDatos.InfoExamen[] infoExamenes = prof.verNotasDelExamen(aIdExamen);

        return infoExamenes;
    }

    public void contestarPregunta(String aIdExamenEsp, String aIdPregunta, String aIdRespuesta) {
        Alumno a = (Alumno) _usuario;
        a.contestarPregunta(aIdExamenEsp, aIdPregunta, aIdRespuesta);
    }

    public Aviso verNotificacion(String aIdNotificacion) {
        return _usuario.verNotificacion(aIdNotificacion);
    }

    public InfoExamenEspecifico generarExamen(String aIdExamen) throws excepcion {
        Alumno alu = (Alumno) _usuario;

        try {
            ExamenEspecifico ee = _aulaVirtual.generarExamen(aIdExamen, alu);
            InfoExamenEspecifico iee = ee.getExamenCompleto();

            return iee;
        } catch (Exception e) {
            PaqDatos.excepcion ex = new excepcion();
            ex.msg = e.getMessage();

            throw ex;
        }
    }

    public InfoAsignatura[] getAsignaturas() throws PaqDatos.excepcion {
        ArrayList<Asignatura> asignaturas = _aulaVirtual.getAsignaturas();
        InfoAsignatura[] retorno = new InfoAsignatura[asignaturas.size()];

        if (asignaturas.size() == 0) {
            throw new PaqDatos.excepcion("El usuario no está matriculado en ninguna asignatura");
        }

        for (int i = 0; i < asignaturas.size(); i++) {
            String nombreAsignatura = asignaturas.get(i).getNombre();

            retorno[i] = new InfoAsignatura();
            retorno[i].idAsignatura = nombreAsignatura;
            retorno[i].matriculado = (_usuario.findAsignatura(nombreAsignatura) != null);
        }

        return retorno;
    }

    public String[] getTemasAsignatura(String idAsignatura) throws PaqDatos.excepcion {
        Asignatura asignatura = _aulaVirtual.findAsignatura(idAsignatura);

        if (asignatura != null) {
            ArrayList<Tema> temas = asignatura.getTemas();
            String[] retorno = new String[temas.size()];

            for (int i = 0; i < temas.size(); i++) {
                retorno[i] = temas.get(i).getNombre();
            }

            return retorno;
        } else {
            throw new PaqDatos.excepcion("No existe la asignatura " + idAsignatura + " o el usuario no está matriculado en ella");
        }
    }

    public InfoExamen[] getExamenes() throws PaqDatos.excepcion {
        InfoExamen[] ie = null;

        if (_usuario instanceof Alumno) {
            ArrayList<ExamenEspecifico> examenes = _usuario.getExamenesRealizados();
            ie = new InfoExamen[examenes.size()];

            for (int i = 0; i < examenes.size(); i++) {
                ie[i] = new InfoExamen();
                ie[i].idExamen = examenes.get(i).getExamen().getIdExamen();
                ie[i].nombre = examenes.get(i).getExamen().getAsignatura().getNombre() + " " + examenes.get(i).getExamen().getFecha();
                ie[i].nota = examenes.get(i).getNota();
            }

        }

        if (_usuario instanceof Profesor) {
            Profesor prof = (Profesor) _usuario;
            ArrayList<Examen> examenes = prof.getExamenesProf();
            ie = new InfoExamen[examenes.size()];

            for (int i = 0; i < examenes.size(); i++) {
                ie[i] = new InfoExamen();
                ie[i].idExamen = examenes.get(i).getIdExamen();
                ie[i].nombre = "No realizado";
                ie[i].nota = 0;
            }
        }

        if (ie == null) {
            PaqDatos.excepcion ex = new PaqDatos.excepcion();
            ex.msg = "Para ver la nota de los examenes se debe especificar la asignatura.";

            throw ex;
        } else if (ie.length == 0) {
            PaqDatos.excepcion ex = new PaqDatos.excepcion();
            ex.msg = "El alumno no ha realizado ningún examen.";

            throw ex;
        }

        return ie;
    }

    public void enviarAviso(String msg) {
        socketComAvisos.enviar("avisar");
        socketComAvisos.enviar(msg);
    }

    public Usuario getUsuario() {
        return _usuario;
    }

    public InfoNotificacionExamen[] getNotificacionesExamen() {
        ArrayList<Aviso> avisos = _usuario.getAvisos();
        ArrayList<AvisoInformacion> ai = new ArrayList<AvisoInformacion>();

        for (int i = 0; i < avisos.size(); i++) {
            if (avisos.get(i) instanceof AvisoInformacion) {
                ai.add((AvisoInformacion) avisos.get(i));
            }
        }

        InfoNotificacionExamen[] ine = new InfoNotificacionExamen[ai.size()];
        for (int i = 0; i < ai.size(); i++) {
            ine[i] = new InfoNotificacionExamen();
            ine[i].idNotificacion = ai.get(i).getIdAviso();
            ine[i].fechaFin = ai.get(i).getExamen().getFechaFinal().toString();
            ine[i].fechaIni = ai.get(i).getExamen().getFechaInicial().toString();
            ine[i].idExamen = ai.get(i).getExamen().getIdExamen();
            ine[i].leido = ai.get(i).getLeido();
            ine[i].corregido = ai.get(i).getExamen().getCorreccion();
        }
        return ine;
    }

    public void terminarExamen(String idExamen, InfoExamenEspecifico iee) {
        if (_usuario instanceof Alumno) {
            Alumno a = (Alumno) _usuario;

            for (int i = 0; i < iee.preguntas.length; i++) {
                for (int j = 0; j < iee.preguntas[i].respuestas.length; j++) {
                    if (iee.preguntas[i].respuestas[j].marcada) {
                        a.contestarPregunta(idExamen, iee.preguntas[i].enunciadoPregunta, iee.preguntas[i].respuestas[j].respuesta);
                    }
                }
            }

            a.terminarExamen(idExamen);
        }
    }

    public InfoExamenEspecifico verExamenEspecificoAlumno(String idExamen, String idAlumno) {
        Alumno a = (Alumno) _aulaVirtual.findUser(idAlumno);

        ArrayList<ExamenEspecifico> examenesRealizados = a.getExamenesRealizados();

        for (int i = 0; i < examenesRealizados.size(); i++) {
            if (idExamen.equals(examenesRealizados.get(i).getExamen().getIdExamen())) {
                return examenesRealizados.get(i).getExamenCompleto();
            }
        }


        return null;
    }

    public void setNoficacionLeida(String idAviso) {
        _usuario.verNotificacion(idAviso);
    }

    void setUsuario(Usuario u) {
        _usuario = u;
    }
}
